﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BLL;
using DLL;
using Logging;
using QuanLyBanLe.Constants;

namespace QuanLyBanLe
{
    public partial class FormOutProdPaper : Form
    {
        private OutProductService m_OutProductService;
        private ProductService m_ProductService;
        private ProductTypeService m_ProductTypeService;
        private ProducerService m_ProducerService;
        private ShopService m_ShopService;
        private InProductService m_ToShopInProdService;
        private ProductService m_ToShopProductService;

        private IList<Product> m_Products;
        private IList<Product> m_NewProducts;
        private IList<ProductType> m_ProductTypes;
        private IList<Producer> m_Producers;

        private bool m_DataChanged;
        private bool m_EnableEvent;
        private int m_OutProdPaperId;
        private FormMode m_Mode;
        private int? m_ToShopId;
        private Shop m_Shop;
        private int m_ReferInProdPaperId;
        private List<pOutProdDetail_Get_Result> m_OutProdDetails;
        private SortOrder m_SortOrder;
        private string m_SortColumn;

        #region Initials
        // New Mode
        public FormOutProdPaper(int? toShopId = null)
        {
            InitializeComponent();
            InitServices();
            m_DataChanged = false;
            m_EnableEvent = false;
            m_OutProdPaperId = 0;
            m_Mode = FormMode.ADD;
            m_ToShopId = toShopId;
            m_ReferInProdPaperId = 0;
            BindData();
        }

        // View Mode
        public FormOutProdPaper(int paperId, DateTime outDate, int? toShopId = 0)
        {
            InitializeComponent();
            InitServices();
            m_OutProdPaperId = paperId;
            m_ToShopId = toShopId;
            InitData(outDate);
            BindData();
            m_OutProdDetails = m_OutProductService.GetOutProdDetails(m_OutProdPaperId);
            BindDetailData();
            dtgOutProdPaper.AllowUserToAddRows = false;
            dtpOutDate.Enabled = false;
            m_Mode = FormMode.VIEW;
        }

        // Update mode
        public FormOutProdPaper(int paperId, DateTime outDate, bool isUpdated, int? toShopId = 0)
        {
            InitializeComponent();
            InitServices();
            m_OutProdPaperId = paperId;
            dtpOutDate.Value = outDate;
            m_ToShopId = toShopId;
            BindData();
            m_OutProdDetails = m_OutProductService.GetOutProdDetails(m_OutProdPaperId);
            BindDetailDataForUpdate();
            if (isUpdated)
            {
                dtpOutDate.Enabled = true;
                btnSave.Visible = true;
            }
            else
            {
                dtpOutDate.Enabled = false;
            }
            m_Mode = FormMode.UPDATE;
        }

        private void InitServices()
        {
            m_OutProductService = new OutProductService();
            m_ProducerService = new ProducerService();
            m_ProductService = new ProductService();
            m_ProductTypeService = new ProductTypeService();
            m_ShopService = new ShopService();
        }

        private void InitData(DateTime outDate)
        {
            dtpOutDate.Value = outDate;
            dtpOutDate.Enabled = false;
            dtgOutProdPaper.Columns["colProductType"].Visible = false;
            dtgOutProdPaper.Columns["colProducer"].Visible = false;
            dtgOutProdPaper.Columns["colDelete"].Visible = false;
            dtgOutProdPaper.Columns["colAmount"].ReadOnly = true;
            dtgOutProdPaper.Columns["colProduct"].ReadOnly = true;
            dtgOutProdPaper.Columns["colAmount"].Width = 200;
            dtgOutProdPaper.Columns["colProduct"].Width = 350;
        }
        #endregion Initials

        #region DatagridView events
        private void dtgOutProdPaper_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (m_Mode != FormMode.VIEW)
            {
                if (e.ColumnIndex == dtgOutProdPaper.Columns["colDelete"].Index && e.RowIndex != -1 && !dtgOutProdPaper.CurrentRow.IsNewRow)
                {
                    DialogResult dialogResult = MessageBox.Show("Bạn có muốn xóa không ?", "Thông báo", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (dialogResult == DialogResult.Yes)
                    {
                        try
                        {
                            var row = dtgOutProdPaper.Rows[e.RowIndex];
                            var idColumn = row.Cells["colId"].Value;
                            if (idColumn != null)
                            {
                                int id = Convert.ToInt32(idColumn.ToString());
                                OutProdDetail oldOutProdDetail = null;
                                if (m_Shop != null)
                                {
                                    oldOutProdDetail = m_OutProductService.GetOutProdDetailById(id);
                                }
                                m_OutProductService.DeleteOutProdDetail(id);

                                if (m_Shop != null)
                                {
                                    // Delete corresponding in prod detail in toShop's database
                                    int referInProdDetailId = Convert.ToInt32(row.Cells["colReferInProdDetailId"].Value);
                                    try
                                    {
                                        m_ToShopInProdService.DeleteInProdDetail(referInProdDetailId);
                                    }
                                    catch (Exception ex)
                                    {
                                        // Revert delete out prod detail
                                        m_OutProductService.AddOutProdDetail(oldOutProdDetail.Amount, oldOutProdDetail.ProductId,
                                            oldOutProdDetail.OutProdPaperId);

                                        MyLogger.LogException("Lỗi xảy ra khi xóa chi tiết nhập kho bên cửa hàng đến", ex);
                                        MessageBox.Show("Không thể xóa chi tiết nhập kho bên cửa hàng đến, vui lòng kiểm tra kến nối", "Thông báo",
                                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                                        row.ErrorText = "Không thể xóa chi tiết nhập kho bên cửa hàng đến";
                                        return;
                                    }
                                }
                            }
                            dtgOutProdPaper.Rows.RemoveAt(e.RowIndex);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("Không thể xóa chi tiết nhập kho vì: " + ex.Message, "Thông báo", MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                            MyLogger.LogException("Lỗi xảy ra khi xóa chi tiết xuất kho", ex);
                        }
                    }
                }
            }
        }

        private void dtgOutProdPaper_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            int currentColumnIndex = dtgOutProdPaper.CurrentCell.ColumnIndex;
            if (e.Control is ComboBox)
            {
                var cbo = e.Control as ComboBox;
                cbo.DropDownStyle = ComboBoxStyle.DropDown;
                cbo.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
                cbo.AutoCompleteSource = AutoCompleteSource.ListItems;
                cbo.KeyDown -= new KeyEventHandler(cbo_KeyDown);
                cbo.KeyDown += new KeyEventHandler(cbo_KeyDown);

                if (currentColumnIndex == dtgOutProdPaper.Columns["colProduct"].Index)
                {
                    var m_ProductComboBox = cbo;
                    // To avoid register twice, remove handler before register
                    m_ProductComboBox.SelectedIndexChanged -= new EventHandler(m_ProductComboBox_SelectedIndexChanged);
                    m_ProductComboBox.SelectedIndexChanged += new EventHandler(m_ProductComboBox_SelectedIndexChanged);
                }
            }
            if (dtgOutProdPaper.CurrentCell.ColumnIndex == dtgOutProdPaper.Columns["colAmount"].Index)
            {
                TextBox item = e.Control as TextBox;
                if (item != null)
                {
                    item.KeyPress -= new KeyPressEventHandler(item_KeyPress);
                    item.KeyPress += new KeyPressEventHandler(item_KeyPress);
                }
            }
        }

        private void cbo_KeyDown(object sender, KeyEventArgs e)
        {
            ComboBox cbo = sender as ComboBox;
            if (cbo.DroppedDown)
            {
                cbo.DroppedDown = false;
            }
        }

        private void m_ProductComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox cbo = sender as ComboBox;
            if (m_EnableEvent && dtgOutProdPaper.CurrentCell != null
                 && cbo.SelectedIndex > -1 && cbo.SelectedValue is int
                 && ((dtgOutProdPaper.CurrentCell.Value == null && dtgOutProdPaper.CurrentCell.Value == DBNull.Value) || ((int)dtgOutProdPaper.CurrentCell.Value != (int)cbo.SelectedValue))
                && dtgOutProdPaper.CurrentCell.ColumnIndex == dtgOutProdPaper.Columns["colProduct"].Index)
            {
                m_EnableEvent = false;
                int productId = Convert.ToInt32(cbo.SelectedValue);
                var product = m_Products.Where(x => x.Id == productId).FirstOrDefault();
                dtgOutProdPaper.CurrentRow.Cells["colProductType"].Value = product.ProductTypeId;
                dtgOutProdPaper.CurrentRow.Cells["colProducer"].Value = product.ProducerId;
                dtgOutProdPaper.CurrentRow.Cells["colProduct"].Value = product.Id;
                dtgOutProdPaper.CurrentRow.Cells["colRemainAmount"].Value = product.Amount;
                m_DataChanged = true;
                m_EnableEvent = true;
            }
        }

        private void item_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!char.IsControl(e.KeyChar)
                && !char.IsDigit(e.KeyChar))
            {
                e.Handled = true;
            }
        }

        private void dtgOutProdPaper_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            if (m_EnableEvent && e.ColumnIndex != dtgOutProdPaper.Columns["colRowNumber"].Index)
            {
                m_EnableEvent = false;
                if (dtgOutProdPaper[e.ColumnIndex, e.RowIndex].Value != null)
                {
                    string temp = dtgOutProdPaper[e.ColumnIndex, e.RowIndex].Value.ToString();                    
                    if (e.ColumnIndex == dtgOutProdPaper.Columns["colProduct"].Index ||
                         e.ColumnIndex == dtgOutProdPaper.Columns["colAmount"].Index)
                    {
                        int cellValue = 0;
                        if (int.TryParse(temp, out cellValue))
                        {
                            if ((e.ColumnIndex == dtgOutProdPaper.Columns["colProduct"].Index && cellValue > 0)
                                || e.ColumnIndex == dtgOutProdPaper.Columns["colAmount"].Index)
                            {
                                m_DataChanged = true;
                            }
                        }
                    }                    
                }
                m_EnableEvent = true;
            }
        }

        private void dtgOutProdPaper_RowValidated(object sender, DataGridViewCellEventArgs e)
        {
            if (m_DataChanged)
            {
                AddOrUpdateDetail(e.RowIndex);
                m_DataChanged = false;
            }
        }

        private void dtgOutProdPaper_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (m_EnableEvent)
            {
                for (int i = 0; i < dtgOutProdPaper.Rows.Count - 1; i++)
                {
                    dtgOutProdPaper["colRowNumber", i].Value = i + 1;

                }
                m_DataChanged = false;
            }
        }

        private void dtgOutProdPaper_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            if (e.ColumnIndex == dtgOutProdPaper.Columns["colProduct"].Index)
            {
                var cellProductType = dtgOutProdPaper.Rows[e.RowIndex].Cells["colProductType"];
                var cellProducer = dtgOutProdPaper.Rows[e.RowIndex].Cells["colProducer"];
                if (cellProductType.Value != null && cellProducer.Value != null)
                {
                    int productTypeId = Convert.ToInt32(cellProductType.Value);
                    int producerId = Convert.ToInt32(cellProducer.Value);
                    if (productTypeId != 0 || producerId != 0)
                    {
                        IList<Product> products = m_ProductService.GetProductsByTypeAndProducer(productTypeId, producerId);
                        Product allProduct = new Product();
                        allProduct.Id = 0;
                        allProduct.Name = "Tất cả";
                        products.Insert(0, allProduct);
                        DataGridViewComboBoxCell cellProduct = (DataGridViewComboBoxCell)dtgOutProdPaper[e.ColumnIndex, e.RowIndex];
                        cellProduct.DataSource = products;
                        cellProduct.ValueMember = "Id";
                        cellProduct.DisplayMember = "Name";

                        // reset value of product column if product type or producer is changed, so the old product is not belong to new colllection of new products
                        var existingProduct = products.Where(p => p.Id == Convert.ToInt32(cellProduct.Value)).FirstOrDefault();
                        if (existingProduct == null)
                        {
                            cellProduct.Value = 0; // reset to "all product"
                        }
                    }
                    else
                    {
                        DataGridViewComboBoxCell cellProduct = (DataGridViewComboBoxCell)dtgOutProdPaper[e.ColumnIndex, e.RowIndex];
                        cellProduct.DataSource = m_NewProducts;
                        cellProduct.ValueMember = "Id";
                        cellProduct.DisplayMember = "Name";
                    }
                }
            }
        }

        private void dtgOutProdPaper_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e)
        {
            // set defaut value for dropdown columns in grid
            e.Row.Cells["colProductType"].Value = 0;
            e.Row.Cells["colProducer"].Value = 0;
            e.Row.Cells["colProduct"].Value = 0;
        }

        private void dtgOutProdPaper_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            //if (dtgOutProdPaper.IsCurrentCellDirty)
            //{
            //    int productId = Convert.ToInt32(dtgOutProdPaper.CurrentRow.Cells["colProduct"].Value);
            //    if (productId > 0)
            //    {
            //        dtgOutProdPaper.CommitEdit(DataGridViewDataErrorContexts.Commit);
            //    }
            //}
        }

        private void dtgOutProdPaper_CellEnter(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == dtgOutProdPaper.Columns["colProduct"].Index)
            {
                int inProdDetailId = Convert.ToInt32(dtgOutProdPaper.Rows[e.RowIndex].Cells["colId"].Value);
                if (inProdDetailId > 0)
                {
                    dtgOutProdPaper.Rows[e.RowIndex].Cells["colProduct"].ReadOnly = true;
                    dtgOutProdPaper.Rows[e.RowIndex].Cells["colProductType"].ReadOnly = true;
                    dtgOutProdPaper.Rows[e.RowIndex].Cells["colProducer"].ReadOnly = true;
                }
            }
        }

        private void dtgOutProdPaper_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            // Show warning message when amount > remain amount
            if (e.ColumnIndex == dtgOutProdPaper.Columns["colAmount"].Index)
            {
                int remainAmount = Convert.ToInt32(dtgOutProdPaper["colRemainAmount", e.RowIndex].Value);
                int oldAmount = Convert.ToInt32(dtgOutProdPaper["colAmount", e.RowIndex].Value);
                int newAmount = Convert.ToInt32(e.FormattedValue);
                if (newAmount - oldAmount > remainAmount)
                {
                    DialogResult result = MessageBox.Show("Số lượng xuất lớn hơn số lượng hàng trong kho, bạn có chắc muốn tiếp tục xuất",
                        "Thông báo", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                    if (result == DialogResult.No)
                    {
                        e.Cancel = true;
                    }
                }
            }
        }
        #endregion DatagridView events

        #region Other Events
        private void FormOutProdPaper_Load(object sender, EventArgs e)
        {
            this.Text += FormMain.GetShopInfo();
            m_EnableEvent = true;
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            // Update out paper
            if (m_OutProdPaperId > 0)
            {
                try
                {
                    DateTime? oldDate = null;
                    if (m_Shop != null)
                    {
                        oldDate = m_OutProductService.GetOutProdPaperById(m_OutProdPaperId).Date;
                    }
                    OutProdPaper paper = new OutProdPaper
                    {
                        Id = m_OutProdPaperId,
                        Date = dtpOutDate.Value
                    };
                    m_OutProductService.UpdateOutPaper(paper);
                    if (m_Shop != null)
                    {
                        try
                        {
                            // Update corresponding in prod paper
                            InProdPaper inPaper = new InProdPaper
                            {
                                Id = m_ReferInProdPaperId,
                                Date = dtpOutDate.Value
                            };
                            m_ToShopInProdService.UpdateInProdPaper(inPaper);
                        }
                        catch (Exception ex)
                        {
                            // Revert update out prod paper
                            paper = new OutProdPaper
                            {
                                Id = m_OutProdPaperId,
                                Date = oldDate.Value
                            };
                            m_OutProductService.UpdateOutPaper(paper);
                            MyLogger.LogException("Lỗi xảy ra khi cập nhập thông tin phiếu xuất bên cửa hàng đến", ex);
                            dtpOutDate.Value = oldDate.Value;
                            MessageBox.Show("Không thể cập nhật phiếu xuất bên cửa hàng đến vì: " + ex.Message, "Thông báo",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);                            
                            return;
                        }
                    }
                    MessageBox.Show("Cập nhật thành công", "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    btnSave.Enabled = false;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Cập nhật không thành công vì: " + ex.Message, "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    MyLogger.LogException("Lỗi xảy ra khi cập nhật thông tin phiếu xuất kho", ex);
                }
            }
            else
            {
                MessageBox.Show("Phiếu xuất kho chưa được tạo nên không thể cập nhật", "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void dtpOutDate_ValueChanged(object sender, EventArgs e)
        {
            if (m_EnableEvent && m_OutProdPaperId > 0)
            {
                btnSave.Enabled = true;
            }
        }

        private void btnPrint_Click(object sender, EventArgs e)
        {
            if (m_OutProdPaperId > 0)
            {
                List<pOutProdDetail_Get_Result> outProdDetails = m_OutProductService.GetOutProdDetails(m_OutProdPaperId);
                string toShop = string.Empty;
                if (m_Shop != null)
                {
                    toShop = m_Shop.Name;
                }
                FormOutProdPaperPrint frm = new FormOutProdPaperPrint(outProdDetails, dtpOutDate.Value, toShop);
                frm.ShowDialog();
            }
            else
            {
                MessageBox.Show("Vui lòng lưu phiếu xuất kho trước khi in", "Thông báo", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            if (m_Mode != FormMode.VIEW)
            {
                if (m_DataChanged)
                {
                    if (ValidateGridData(dtgOutProdPaper.CurrentRow.Index))
                    {
                        DialogResult dialogResult = MessageBox.Show("Dữ liệu thay đổi bạn có muốn lưu lại không ?", "Thông báo", MessageBoxButtons.YesNo);
                        if (dialogResult == System.Windows.Forms.DialogResult.Yes)
                        {
                            AddOrUpdateDetail(dtgOutProdPaper.CurrentRow.Index);
                        }
                    }
                }
                if (dtgOutProdPaper.Rows.Count == 1 && Convert.ToInt32(dtgOutProdPaper.Rows[0].Cells["colId"].Value) == 0)
                {
                    try
                    {
                        m_OutProductService.DeleteOutProdPaper(m_OutProdPaperId);

                        // Delete corresponding in prod paper
                        if (m_Shop != null)
                        {
                            try
                            {
                                m_ToShopInProdService.DeleteInProdPaper(m_ReferInProdPaperId);
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("Lỗi xảy ra khi xóa phiếu nhập kho bên cửa hàng đến liên quan đến phiếu xuất kho vì: " + ex.Message,
                                    "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                MyLogger.LogException("Lỗi xảy ra khi xóa phiếu nhập kho bên cửa hàng đến liên quan đến phiếu xuất kho", ex);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Lỗi xảy ra khi xóa phiếu xuất kho vì: " + ex.Message,
                                   "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        MyLogger.LogException("Lỗi xảy ra khi xóa phiếu xuất kho", ex);
                    }
                }
            }
            base.OnClosing(e);
        }
        #endregion Other Events

        #region Methods
        private void BindDetailData()
        {
            dtgOutProdPaper.Rows.Clear();
            if (m_OutProdDetails.Count > 0)
            {
                for (int i = 0; i < m_OutProdDetails.Count; i++)
                {
                    var detail = m_OutProdDetails[i];
                    var product = m_Products.Where(x => x.Id == detail.ProductId).FirstOrDefault();
                    dtgOutProdPaper.Rows.Add((i + 1).ToString());
                    dtgOutProdPaper.Rows[i].Cells["colId"].Value = detail.Id;
                    dtgOutProdPaper.Rows[i].Cells["colAmount"].Value = detail.Amount;
                    dtgOutProdPaper.Rows[i].Cells["colProduct"].Value = detail.ProductId;
                    dtgOutProdPaper.Rows[i].Cells["colRemainAmount"].Value = product.Amount;
                    dtgOutProdPaper.Rows[i].Cells["colProduct"].ReadOnly = true;
                }
            }
        }

        private void BindDetailDataForUpdate()
        {
            dtgOutProdPaper.Rows.Clear();
            if (m_Shop != null)
            {
                // Get Refer In Prode Paper Id
                OutProdPaper outProdPaper = m_OutProductService.GetOutProdPaperById(m_OutProdPaperId);
                if (outProdPaper != null)
                {
                    m_ReferInProdPaperId = outProdPaper.ReferInProdPaperId.Value;
                }
            }
            if (m_OutProdDetails.Count > 0)
            {
                for (int i = 0; i < m_OutProdDetails.Count; i++)
                {
                    var detail = m_OutProdDetails[i];
                    var product = m_Products.Where(x => x.Id == detail.ProductId).FirstOrDefault();                    
                    dtgOutProdPaper.Rows.Add((i + 1).ToString());
                    dtgOutProdPaper.Rows[i].Cells["colAmount"].Value = detail.Amount;
                    dtgOutProdPaper.Rows[i].Cells["colId"].Value = detail.Id;
                    dtgOutProdPaper.Rows[i].Cells["colProductType"].Value = detail.ProductTypeId;
                    dtgOutProdPaper.Rows[i].Cells["colProducer"].Value = detail.ProducerId;
                    dtgOutProdPaper.Rows[i].Cells["colProduct"].Value = detail.ProductId;
                    dtgOutProdPaper.Rows[i].Cells["colRemainAmount"].Value = product.Amount;
                    dtgOutProdPaper.Rows[i].Cells["colReferInProdDetailId"].Value = detail.ReferInProdDetailId;
                }
            }
        }

        private void BindData()
        {
            m_ProductTypes = m_ProductTypeService.GetProductTypes();
            ProductType allProductType = new ProductType();
            allProductType.Id = 0;
            allProductType.Name = "Tất cả";
            m_ProductTypes.Insert(0, allProductType);

            m_Producers = m_ProducerService.GetProducers();
            Producer allProducer = new Producer();
            allProducer.Id = 0;
            allProducer.Name = "Tất cả";
            m_Producers.Insert(0, allProducer);

            m_Products = m_ProductService.GetProducts(true);
            Product allProduct = new Product();
            allProduct.Id = 0;
            allProduct.Name = "Tất cả";
            allProduct.IsDeleted = false;
            m_Products.Insert(0, allProduct);
            m_NewProducts = m_Products.Where(x => x.IsDeleted == false).ToList();

            colProducer.DataSource = m_Producers;
            colProducer.ValueMember = "Id";
            colProducer.DisplayMember = "Name";

            colProductType.DataSource = m_ProductTypes;
            colProductType.ValueMember = "Id";
            colProductType.DisplayMember = "Name";

            colProduct.DataSource = m_Products;
            colProduct.ValueMember = "Id";
            colProduct.DisplayMember = "Name";

            if (m_ToShopId.HasValue)
            {
                m_Shop = m_ShopService.GetById(m_ToShopId.Value);
                lblTo.Text = "Đến: " + m_Shop.Name;
                m_ToShopInProdService = new InProductService(DbContextFactory.CreateConnectionString(m_Shop.ConnectionString));
                m_ToShopProductService = new ProductService(DbContextFactory.CreateConnectionString(m_Shop.ConnectionString));
            }
            else
            {
                lblTo.Text = string.Empty;
                m_Shop = null;
            }
        }

        private void AddOrUpdateDetail(int index)
        {
            try
            {
                if (ValidateGridData(index))
                {
                    var row = dtgOutProdPaper.Rows[index];
                    var idColumn = row.Cells["colId"].Value;
                    int amount = Convert.ToInt32(row.Cells["colAmount"].Value);
                    int productId = Convert.ToInt32(row.Cells["colProduct"].Value);
                    if (productId > 0 && amount > 0)
                    {
                        m_EnableEvent = false;
                        m_DataChanged = false;
                        OutProdDetail detail = new OutProdDetail()
                        {
                            Amount = amount,
                            OutProdPaperId = m_OutProdPaperId,
                            ProductId = productId,
                        };
                        if (idColumn == null) // Add
                        {
                            AddOutProdDetail(detail, row);
                        }
                        else // Update
                        {
                            UpdateOutProdDetail(detail, row);
                        }
                        if (m_Mode == FormMode.UPDATE)
                        {
                            m_OutProdDetails = m_OutProductService.GetOutProdDetails(m_OutProdPaperId);
                        }
                        m_EnableEvent = true;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Không thể thêm hoặc cập nhật phiếu nhập do lỗi: " + ex.Message, "Thông báo", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                MyLogger.LogException("Lỗi xảy ra khi thêm hoặc cập nhật phiếu nhập", ex);
            }
        }

        private Product CheckDesProductExistInToShop(int productId)
        {
            Product desProduct = null;

            Product srcProduct = m_Products.Where(x => x.Id == productId).FirstOrDefault();
            string srcProductName = srcProduct.Name;

            // Check to shop already has product name
            try
            {
                desProduct = m_ToShopProductService.GetProductByName(srcProductName);
            }
            catch (Exception ex)
            {
                MyLogger.LogException("Lỗi xảy ra khi tìm sản phẩm bên cửa hàng đến", ex);
            }
            return desProduct;
        }

        private void ProcessInsertInProdDetailFail(int outProdDetailId, int outProdPaperId, bool addedOutPaper, DataGridViewRow row)
        {
            // Revert out prod paper and detail added
            m_OutProductService.DeleteOutProdDetail(outProdDetailId);
            if (addedOutPaper)
            {
                m_OutProductService.DeleteOutProdPaper(outProdPaperId);
            }
            row.ErrorText = "Không thể thêm chi tiết nhập kho bên cửa hàng đến";
            MessageBox.Show("Không thể thêm chi tiết nhập kho bên cửa hàng đến, vui lòng kiểm tra lại kết nối", "Thông báo",
                               MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void ProcessUpdateReferIdFail(int inProdDetailId, int inProdPaperId, bool addedInPaper,
            int outProdDetailId, int outProdPaperId, bool addedOutPaper,
            DataGridViewRow row)
        {
            // Revert out prod paper and detail added
            m_OutProductService.DeleteOutProdDetail(outProdDetailId);
            if (addedOutPaper)
            {
                m_OutProductService.DeleteOutProdPaper(outProdPaperId);
            }

            // Revert in prod paper and detail added
            m_ToShopInProdService.DeleteInProdDetail(inProdDetailId);
            if (addedInPaper)
            {
                m_ToShopInProdService.DeleteInProdPaper(inProdPaperId);
            }
            row.ErrorText = "Không thể cập nhật mã nhập kho liên quan";

            MessageBox.Show("Không thể cập nhật mã nhập kho liên quan, vui lòng kiểm tra lại kết nối", "Thông báo",
                                       MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void AddOutProdDetail(OutProdDetail detail, DataGridViewRow row)
        {
            Product desProduct = null;
            if (m_Shop != null)
            {
                desProduct = CheckDesProductExistInToShop(detail.ProductId);
                if (desProduct == null)
                {
                    MessageBox.Show("Không có sản phẩm tương ứng bên cửa hàng đến, vui lòng thêm sản phẩm này vào cửa hàng đến", "Thông báo",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                    row.ErrorText = "Không có sản phẩm tương ứng bên cửa hàng đến";
                    return; // Break
                }
            }

            var addOutProdDetailResult = m_OutProductService.AddOutProdDetail(detail.Amount, detail.ProductId,
                               m_OutProdPaperId, dtpOutDate.Value, FormMain.s_User.Id, m_ToShopId);
            if (addOutProdDetailResult.ReturnValue == 0) // Success
            {
                bool addedOutPaper = false; // indicate out prod paper is inserted
                if (m_OutProdPaperId == 0)
                {
                    addedOutPaper = true;
                }

                // Add in prod detail to database of toshop
                if (m_Shop != null)
                {
                    // Add in prod detail
                    Product srcProduct = m_Products.Where(x => x.Id == detail.ProductId).FirstOrDefault();
                    try
                    {
                        var addInProdDetailResult = m_ToShopInProdService.AddInProdDetail(detail.Amount, desProduct.Id, srcProduct.LatestInputPrice.Value,
                            m_ReferInProdPaperId, -1, dtpOutDate.Value);
                        if (addInProdDetailResult.ReturnValue == 0) // Success
                        {
                            bool addedInPaper = false; // indicate in prod paper is inserted
                            if (m_ReferInProdPaperId == 0)
                            {
                                addedInPaper = true;
                            }
                            try
                            {
                                // Update refer id of out prod paper and out prod detail
                                var updateReferIdResult = m_OutProductService.UpdateReferId(addOutProdDetailResult.OutProdPaperId.Value, addOutProdDetailResult.Id.Value,
                                    addInProdDetailResult.InProdPaperId.Value, addInProdDetailResult.Id.Value);
                                if (updateReferIdResult == 0) // Success
                                {
                                    row.ErrorText = "";
                                    m_ReferInProdPaperId = addInProdDetailResult.InProdPaperId.Value;
                                    row.Cells["colReferInProdDetailId"].Value = addInProdDetailResult.Id.Value;
                                }
                                else
                                {
                                    ProcessUpdateReferIdFail(addInProdDetailResult.Id.Value,
                                        m_ReferInProdPaperId, addedInPaper, addOutProdDetailResult.Id.Value, m_OutProdPaperId,
                                        addedOutPaper, row);
                                    return;
                                }
                            }
                            catch (Exception ex)
                            {
                                ProcessUpdateReferIdFail(addInProdDetailResult.Id.Value,
                                       m_ReferInProdPaperId, addedInPaper, addOutProdDetailResult.Id.Value, m_OutProdPaperId,
                                       addedOutPaper, row);
                                MyLogger.LogException("Lỗi xảy ra khi cập nhật mã nhập kho liên quan", ex);
                                return;
                            }
                        }
                        else
                        {
                            ProcessInsertInProdDetailFail(addOutProdDetailResult.Id.Value, addOutProdDetailResult.OutProdPaperId.Value, addedOutPaper, row);
                            return;
                        }
                    }
                    catch (Exception ex)
                    {
                        ProcessInsertInProdDetailFail(addOutProdDetailResult.Id.Value, addOutProdDetailResult.OutProdPaperId.Value, addedOutPaper, row);
                        MyLogger.LogException("Lỗi xảy ra khi thêm chi tiết nhập kho bên cửa hàng đến", ex);
                        return;
                    }
                }

                m_OutProdPaperId = addOutProdDetailResult.OutProdPaperId.Value;
                row.Cells["colId"].Value = addOutProdDetailResult.Id;
                row.Cells["colAmount"].ErrorText = "";
                btnSave.Visible = true;
                // Update amount of product on grid
                UpdateProductAmount(detail.ProductId);
            }
            else if (addOutProdDetailResult.ReturnValue == -1)
            {
                row.Cells["colAmount"].ErrorText = "Sai số lượng";
                MessageBox.Show("Không thể xuất kho sản phẩm này với số lượng lớn hơn số lượng có trong kho", "Thông báo",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                MessageBox.Show("Lỗi chương trình");
            }
        }

        private void ProcessWhenUpdateInProdDetailFail(int outProdDetailId, int oldAmount, DataGridViewRow row)
        {
            // revert old amount of out prod detail
            m_OutProductService.UpdateOutProdDetail(outProdDetailId, oldAmount);
            row.ErrorText = "Không thể cập nhật chi tiết nhập kho bên cửa hàng đến";

            MessageBox.Show("Không thể cập nhật chi tiết nhập kho bên cửa hàng đến, vui lòng kiểm tra lại kết nối", "Thông báo",
                              MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void UpdateOutProdDetail(OutProdDetail detail, DataGridViewRow row)
        {
            detail.Id = Convert.ToInt32(row.Cells["colId"].Value);
            int oldAmount = 0;
            if (m_Shop != null)
            {
                // get old amount for revert purpose later
                oldAmount = m_OutProductService.GetOutProdDetailById(detail.Id).Amount;
            }
            var result = m_OutProductService.UpdateOutProdDetail(detail.Id, detail.Amount);
            if (result == -1)
            {
                row.Cells["colAmount"].ErrorText = "Sai số lượng";
                MessageBox.Show("Không thể xuất kho sản phẩm này với số lượng lớn hơn số lượng có trong kho", "Thông báo",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else if (result == -2)
            {
                MessageBox.Show("Lỗi chương trình", "Thông báo", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else // Success
            {
                if (m_Shop != null)
                {
                    // Update amount of refer in prod detail
                    int referInProdDetailId = Convert.ToInt32(row.Cells["colReferInProdDetailId"].Value);
                    try
                    {
                        int updateInProdDetailResult = m_ToShopInProdService.UpdateInProdDetail(referInProdDetailId, detail.Amount);
                        if (updateInProdDetailResult == 0)
                        {
                            row.ErrorText = "";
                        }
                        else
                        {
                            ProcessWhenUpdateInProdDetailFail(detail.Id, oldAmount, row);
                            return;
                        }
                    }
                    catch (Exception ex)
                    {
                        ProcessWhenUpdateInProdDetailFail(detail.Id, oldAmount, row);
                        MyLogger.LogException("Lỗi xảy ra khi cập nhật phiếu nhập kho bên cửa hàng đến", ex);
                        return;
                    }
                }

                row.Cells["colAmount"].ErrorText = "";
                // Update amount of product on grid
                UpdateProductAmount(detail.ProductId);
            }
        }

        private bool ValidateGridData(int rowIndex)
        {
            DataGridViewRow row = dtgOutProdPaper.Rows[rowIndex];

            // validate product name
            var data = row.Cells["colProduct"].Value;
            if (data == null || string.IsNullOrWhiteSpace(data.ToString()))
            {
                row.Cells["colProduct"].ErrorText = "Chọn sản phẩm";
                return false;
            }
            else
            {
                row.Cells["colProduct"].ErrorText = "";
            }

            // validate producer
            data = row.Cells["colAmount"].Value;
            if (data == null || data.ToString() == "0")
            {
                row.Cells["colAmount"].ErrorText = "Nhập số lượng";
                return false;
            }
            else
            {
                row.Cells["colAmount"].ErrorText = "";
            }

            return true;
        }

        private void UpdateProductAmount(int productId)
        {
            var product = m_ProductService.GetProductById(productId);
            var product2 = m_Products.Where(x => x.Id == productId).FirstOrDefault();
            product2.Amount = product.Amount;

            //m_Products = m_ProductService.GetProducts(true);
            //Product allProduct = new Product();
            //allProduct.Id = 0;
            //allProduct.Name = "Tất cả";
            //allProduct.IsDeleted = false;
            //m_Products.Insert(0, allProduct);
            //var product = m_Products.Where(x => x.Id == productId).FirstOrDefault();

            m_NewProducts = m_Products.Where(x => x.IsDeleted == false).ToList();
            foreach (DataGridViewRow row in dtgOutProdPaper.Rows)
            {
                var id = Convert.ToInt32(row.Cells["colProduct"].Value);
                if (productId == id)
                {
                    row.Cells["colRemainAmount"].Value = product.Amount;
                }
            }
        }
        #endregion Methods        

        private void dtgOutProdPaper_Sorted(object sender, EventArgs e)
        {
            if (m_Mode != FormMode.ADD)
            {
                var view = (DataGridView)sender;
                m_SortOrder = view.SortOrder;
                m_SortColumn = view.SortedColumn.Name;
                bool isCustomSort = false;
                if (m_SortOrder == SortOrder.Ascending)
                {
                    if (m_SortColumn == "colProduct")
                    {
                        m_OutProdDetails = m_OutProdDetails.OrderBy(x => x.Name).ToList();
                        isCustomSort = true;
                    }
                }
                else
                {
                    if (m_SortColumn == "colProduct")
                    {
                        m_OutProdDetails = m_OutProdDetails.OrderByDescending(x => x.Name).ToList();
                        isCustomSort = true;
                    }
                }

                if (isCustomSort)
                {
                    if (m_Mode == FormMode.VIEW)
                    {
                        BindDetailData();
                    }
                    else
                    {
                        BindDetailDataForUpdate();
                    }
                }
            }
        }
    }
}
